package com.wfw.feichat.netty;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.wfw.feichat.common.MsgActionEnum;
import com.wfw.feichat.entity.Chatmsg;
import com.wfw.feichat.netty.po.ChatMsg;
import com.wfw.feichat.netty.po.DataContent;
import com.wfw.feichat.service.ChatmsgService;
import com.wfw.feichat.utils.SpringUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 处理消息的handler
 * TextWebSocketFrame：在netty中，是用于为websocket专门处理文本的对像，frame是消息的载体
 *
 * @author: wfw
 * @date: 2019-05-21 16:29
 */
@Slf4j
public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {

        Channel currentChannel = channelHandlerContext.channel();

        /**
         * 1.获取客户端传输过来的消息
         * 2.判断消息类型，根据不同的类型来处理不同的业务
         *    1）当websocket第一次open的时候，初始化channel，把用户的channel和userId关联起来
         *    2）聊天类型的消息，把聊天记录保存到数据库，同时标记消息的签收状态：未签收
         *    3）签收消息类型，针对具体的消息进行签收，修改消息的签收状态：已签收
         *    4）心跳类型的消息
         */

        // 获取客户端传输过来的消息
        String content = textWebSocketFrame.text();
        log.info("接收的数据：{}", content);

        DataContent dataContent = JSON.parseObject(content, DataContent.class);

        Integer action = dataContent.getAction();
        ChatMsg chatMsg = dataContent.getChatMsg();

        if (action.equals(MsgActionEnum.CONNECT.getType())) {
            // 1）当websocket第一次open的时候，初始化channel，把用户的channel和userId关联起来

            UserChannelRel.put(chatMsg.getSenderId(), currentChannel);

        } else if (action.equals(MsgActionEnum.CHAT.getType())) {
            // 2）聊天类型的消息，把聊天记录保存到数据库，同时标记消息的签收状态：未签收

            ChatmsgService chatmsgService = (ChatmsgService) SpringUtil.getBean("chatmsgService");

            Chatmsg chatmsg = new Chatmsg();
            chatmsg.setFlag(0);
            chatmsg.setSendUid(chatMsg.getSenderId());
            chatmsg.setAcceptUid(chatMsg.getReceiverId());
            chatmsg.setMsg(chatMsg.getMsg());

            chatMsg.setMsgId(chatmsgService.addChatmsg(chatmsg));

            // 发送消息
            // 从全局channel关系中获取接收方的channel
            Channel receiverChannel = UserChannelRel.get(chatMsg.getReceiverId());
            if (receiverChannel == null) {
                // TODO receiverChannel为空表示接收方离线，使用JPush，个推或小米推送等推送消息
            } else {
                // 当receiverChannel不为空的时候，从channelGroup中去查找对应的channel是否存在
                Channel findChannel = channelGroup.find(receiverChannel.id());
                if (findChannel != null) {
                    // 用户在线,给客户端发送
                    receiverChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(dataContent)));
                } else {
                    // TODO 用户离线，推送
                }
            }
        } else if (action.equals(MsgActionEnum.SIGNED.getType())) {
            // 3）签收消息类型，针对具体的消息进行签收，修改消息的签收状态：已签收

            ChatmsgService chatmsgService = (ChatmsgService) SpringUtil.getBean("chatmsgService");

            if (StringUtils.isNotBlank(dataContent.getExtand())) {
                String msgIds[] = dataContent.getExtand().split(",");

                List<String> msgIdList = Lists.newArrayList();
                for (String msgId : msgIds) {
                    if (StringUtils.isNotBlank(msgId)) {
                        msgIdList.add(msgId);
                    }
                }
                if (msgIdList.size() > 0) {
                    chatmsgService.batchUpdateMsgSigned(msgIdList);
                }
            }

        } else if (action.equals(MsgActionEnum.KEEPPALIVE.getType())) {
            // 4）心跳类型的消息

            log.info("收到来自channel为[{}]的心跳包...", currentChannel);
        }

        // for (Channel channel : channelGroup) {
        //     channel.writeAndFlush(new TextWebSocketFrame("[" + LocalDateTime.now() + "]" + channelHandlerContext.channel().id().asShortText() + ":" + content));
        // }
        // channelGroup.writeAndFlush(new TextWebSocketFrame("[" + LocalDateTime.now().format(dateTimeFormatter) + "]" + channelHandlerContext.channel().id().asShortText() + ":" + content));


    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        channelGroup.add(ctx.channel());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        // 当触发时，channelGroup会自动移除对应客户端的channel
        channelGroup.remove(ctx.channel());
        log.info("客户端断开，channel对应的短id为：{}", ctx.channel().id().asShortText());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("----- netty exceptionCaught -----");
        log.error(cause.getMessage());
        // cause.printStackTrace();
        // 发生异常之后关闭连接（关闭channel），随后从ChannelGroup中移除
        ctx.channel().close();
        channelGroup.remove(ctx.channel());
    }
}
